#include <linux/segment.h>

.globl startup_32
startup_32:
    movl $(KERNEL_DS), %eax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs

    movl $0, %esi
    movl $0x100000, %edi
    movl $0x20000, %ecx
    cld
    rep
    movsd                   # 将内核从0移动到0x100000
    ljmp $(KERNEL_CS), $1f
1:  lss stack_start, %esp   # 设置esp和ss

    # 清空0到0xa0000的数据
    xorl %eax, %eax
    movl $0, %edi
    movl $0x90000, %ecx
    cld
    rep
    stosb

    # 初始化bss段
    xorl %eax, %eax
    movl _bss, %edi
    movl _end, %ecx
    subl %edi, %ecx
    cld
    rep
    stosb

    xorl %eax, %eax
1:  incl %eax               # 检查A20是否开启
    movl %eax, 0x0          # 如果没开启则一直循环
    cmpl %eax, 0x100000
    je 1b

    pushl $0
    popfl                   # 初始化eflags

# empty_zero_page的前2k是启动参数，后2k供命令行使用
    movl $0x90000, %esi
    movl $empty_zero_page, %edi
    movl $512, %ecx
    cld
    rep
    movsl
    xorl %eax, %eax
    movl $512, %ecx
    rep
    stosl

    lgdt gdt_descr
    lidt idt_descr
    ljmp $(KERNEL_CS), $1f
1:  movl $(KERNEL_DS), %eax # 重载段寄存器
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    lss stack_start, %esp   # 重新设置esp和ss
    xorl %eax, %eax
    lldt %ax
    pushl %eax
    pushl %eax
    pushl %eax
    cld
    call start_kernel
    jmp .

.org 0x5000
.globl empty_zero_page
empty_zero_page:

.org 0x6000

.align  4
.word   0
idt_descr:
    .word   256 * 8 - 1
    .long   idt

.align 4
idt:
    .fill 256, 8, 0

.align 4
.word 0
gdt_descr:
    .word   256 * 8 - 1
    .long   gdt

.align  8
gdt:
    .quad   0x0000000000000000  /* NULL descriptor */
    .quad   0x0000000000000000  /* not used */
    .quad   0x00cf9a000000ffff  /* 0x10 kernel 4GB code at 0x00000000 */
    .quad   0x00cf92000000ffff  /* 0x18 kernel 4GB data at 0x00000000 */
    .fill   252, 8, 0
